using System.Collections.Generic;
using System.Data.SqlServerCe;
using System;
using OverStore.Configuration;
using OverStore.Configuration.Components;
using OverStore.Runtime.Storage;
using OverStore.Configuration.Builder;
using OverStore.Sql.TableSchema;
using System.Reflection;
using OverStore.Configuration.Builder.Fluent;
using OverStore.Runtime.ObjectRepository.Mapping;
using OverStore.Runtime.ObjectRepository.ErrorTransformer;

namespace OverStore.TutorialAsTest.UnitTest.Configuration.Rdbms
{
    public class A
    {
        public int Id { get; set; }

        public string Name { get; set; }

        public DateTime CreatedAt { get; set; }
    }

    public class AParams1 : A { }

    public class CreateConfigurationFlowInterface
    {
        private static IComponentConfiguration<IMapper<A>> CreateAMapper()
        {
            return Component.Mapper.Delegate<A>(
                (item, name, p) =>
                {
                    if (name == "Id")
                        return item.Id;
                    if (name == "Name")
                        return item.Name;
                    if (name == "CreatedAt")
                        return item.CreatedAt;
                    if (name == "orig__oid")
                        return p.GetIdentifier<A, int>(item);
                    return Missing.Value;
                },
                (data, item, p) =>
                {
                    item.CreatedAt = data.GetDateTime("CreatedAt");
                    item.Name = data.GetString("Name");
                });
        }

        public static OverStoreConfiguration CreateConfiguration(string connectionString)
        {
            return OverStoreFluent.Configure()
                .LogToConsole().ConnectToDatabase<SqlCeConnection>(connectionString, ProcessOpenedReadersMode.ForciblyCloseReaders)
                .CustomClassRepository<A, int>()
                    .WithDepot(Component.Depot.WithInternalKey<A, int>("Id"))
                    .WithMapper(CreateAMapper())
                    .WithCommands(Component.CommandSet.FromTable(
                                Component.CreateTable("A").Key<int>("Id").Column<string>("Name").Column<DateTime>("CreatedAt"), false))
                    .WithChangesTracker(Component.InstanceChangesTracker.Checksum<A, int>("Id", "Name", "CreatedAt"))
                    .ByIdentifierAttaching(i => i.Id)
                    .ParameterlessReader(false)
                        .ReadCommand()
                            .UseSqlCommand("select * from a")
                        .EndCommand()
                        .WithIdentifierProvider(Component.IdentifierProvider.Delegate<int>(r => r.GetInt32("Id")))
                    .EndReader()
                    .ParameterizedReader<A>(false)
                        .ReadCommand()
                            .UseSqlCommand("select * from a")
                        .EndCommand()
                        .WithParametersMapper(CreateAMapper())
                        .WithIdentifierProvider(Component.IdentifierProvider.Delegate<int>(r => r.GetInt32("Id")))
                    .EndReader()
                .EndObjectRepository()
             .End();
        }

        public static void CreateConfigurationTest(string connectionString)
        {
            OverStoreFluent
                .Configure()
                .LogToConsole()
                .ConnectToDatabase<SqlCeConnection>(connectionString, ProcessOpenedReadersMode.ForciblyCloseReaders)
                .CustomClassRepository<A, int>()
                    .DelegateDepot()
                        .CreateInstance(() => new A())
                        .StoreIdentifier((entity, identifier) => entity.Id = identifier)
                        .Incremental(0, -1)
                    .EndDepot()
                    .MapUsingDelegate()
                        .GetObjectDataUsing(
                            (item, name, p) =>
                            {
                                if (name == "Id")
                                    return item.Id;
                                if (name == "Name")
                                    return item.Name;
                                if (name == "CreatedAt")
                                    return item.CreatedAt;
                                if (name == "orig__oid")
                                    return p.GetIdentifier<A, int>(item);
                                return Missing.Value;
                            })
                        .ApplyDataUsing(
                            (data, item, p) =>
                            {
                                item.CreatedAt = data.GetDateTime("CreatedAt");
                                item.Name = data.GetString("Name");
                            })
                    .CommandsFromTable(
                        false,
                        Component.CreateTable("A")
                            .Key<int>("Id")
                            .Column<string>("Name")
                            .Column<DateTime>("CreatedAt"))
                    .TrackChangesUsingDump(a => { unchecked { return a.Id.GetHashCode(); } })
                    .ErrorTransform()
                        .Transform<SqlCeException>("UK_Name", MessageMatchType.MessageContainsPattern, "Name is not unique.")
                        .Transform<SqlCeException>("UK_CreatedAt", MessageMatchType.MessageContainsPattern, "Created At violation.")
                    .EndErrorTransform()
                    .ByIdentifierAttaching(i => i.Id)
                .EndObjectRepository()
                .MapClassToTable<A, int>("A")
                    .MapKey("Id", e => e.Id, (e, k) => e.Id = k, Component.IdentifierGenerator.Seq<A>(0, -1))
                    .MapScalarValue("Name", e => e.Name, (e, v) => e.Name = v)
                    .ParameterlessReader(true)
                        .WithCommand(null)
                        .DelegateIdentifierProvider(r => r.GetInt32("Id"))
                    .EndReader()
                    .ParameterizedReader<object>(true)
                        .WithReadCommand(null)
                        .MapParametersUsingReflection()
                        .DelegateIdentifierProvider(r => r.GetInt32("Id"))
                    .EndReader()
                .EndTableMapping();
        }
    }
}